package com.xy.core.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.hql.ast.QueryTranslatorImpl;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.xy.common.page.Pagination;
import com.xy.core.command.CriteriaCommand;
import com.xy.core.command.FieldCommandImpl;
import com.xy.core.command.QueryFilter;
import com.xy.core.command.SortCommandImpl;
import com.xy.core.dao.GenericDao;
import com.xy.core.web.paging.PagingBean;

public abstract class GenericDaoImpl<T, PK extends Serializable> extends
		HibernateDaoSupport implements GenericDao<T, PK> {
	protected Log logger = LogFactory.getLog(GenericDaoImpl.class);
	protected JdbcTemplate jdbcTemplate;
	protected Class persistType;
	protected Map<String, String> querys = new HashMap();

	public void setJdbcTemplate(JdbcTemplate paramJdbcTemplate) {
		this.jdbcTemplate = paramJdbcTemplate;
	}

	public void setPersistType(Class paramClass) {
		this.persistType = paramClass;
	}

	public GenericDaoImpl(Class paramClass) {
		this.persistType = paramClass;
	}

	public T get(PK paramPK) {
		return (T) getHibernateTemplate().get(this.persistType, paramPK);
	}

	public T save(T paramT) {
		getHibernateTemplate().saveOrUpdate(paramT);
		return paramT;
	}

	public T merge(T paramT) {
		getHibernateTemplate().merge(paramT);
		return paramT;
	}

	public void evict(T paramT) {
		getHibernateTemplate().evict(paramT);
	}
	protected Pagination findByPage(final String hql,final  Object values[], final int pageNo,final int pageSize) {
		int totalCount = getTotalItems(hql, values).intValue();
		final Pagination p = new Pagination(pageNo, pageSize, totalCount);
		if (totalCount < 1) {
			p.setList(new ArrayList());
			return p;
		}
		List list = getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (values != null) {
					for (int i = 0; i < values.length; i++)
						query.setParameter(i, values[i]);

				}
				query.setFirstResult(p.getFirstResult()).setFetchSize(pageSize);
				query.setMaxResults(pageSize);
				return query.list();
			}

		});
		p.setList(list);
		return p;
	}
	
	public List find(final String queryString, final Object values[],
			final int firstResult, final int pageSize) {
		return (List) getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(queryString);
				if (values != null) {
					for (int i = 0; i < values.length; i++)
						query.setParameter(i, values[i]);

				}
				if (pageSize > 0)
					query.setFirstResult(firstResult).setMaxResults(pageSize)
							.setFetchSize(pageSize);
				return query.list();
			}

		});
	}

	public List<T> getAll() {
		return (List) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session paramSession)
					throws HibernateException, SQLException {
				String str = "from "
						+ GenericDaoImpl.this.persistType.getName();
				Query localQuery = paramSession.createQuery(str);
				return localQuery.list();
			}
		});
	}
	
	public List getAll(final PagingBean pb) {
		final String hql = (new StringBuilder()).append("from ")
				.append(persistType.getName()).toString();
		int i = getTotalItems(hql, null).intValue();
		pb.setTotalItems(i);
		return (List) getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				query.setFirstResult(pb.getFirstResult()).setFetchSize(
						pb.getPageSize().intValue());
				query.setMaxResults(pb.getPageSize().intValue());
				return query.list();
			}

		});
	}

	public Long getTotalItems(String s, final Object values[]) {
		int i = s.toUpperCase().indexOf(" ORDER BY ");
		if (i != -1)
			s = s.substring(0, i);
		QueryTranslatorImpl querytranslatorimpl = new QueryTranslatorImpl(s, s,
				Collections.EMPTY_MAP,
				(SessionFactoryImplementor) getSessionFactory());
		querytranslatorimpl.compile(Collections.EMPTY_MAP, false);
		final String sql = (new StringBuilder())
				.append("select count(*) from (")
				.append(querytranslatorimpl.getSQLString())
				.append(") tmp_count_t").toString();
		Object obj = getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				SQLQuery sqlquery = session.createSQLQuery(sql);
				if (values != null) {
					for (int j = 0; j < values.length; j++)
						sqlquery.setParameter(j, values[j]);

				}
				return sqlquery.uniqueResult();
			}

		});
		return new Long(obj.toString());
	}

	public List findByHql(final String hql, final Object objs[]) {
		return (List) getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (objs != null) {
					for (int i = 0; i < objs.length; i++)
						query.setParameter(i, objs[i]);

				}
				return query.list();
			}

		});
	}

	public List findByHql(final String hql, final Object objs[],
			final int firstResult, final int pageSize) {
		return (List) getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				query.setFirstResult(firstResult).setMaxResults(pageSize);
				if (objs != null) {
					for (int i = 0; i < objs.length; i++)
						query.setParameter(i, objs[i]);

				}
				return query.list();
			}

		});
	}

	public List<T> findByHql(String paramString, Object[] paramArrayOfObject,
			PagingBean paramPagingBean) {
		int i = getTotalItems(paramString, paramArrayOfObject).intValue();
		paramPagingBean.setTotalItems(i);
		return findByHql(paramString, paramArrayOfObject,
				paramPagingBean.getFirstResult(), paramPagingBean.getPageSize()
						.intValue());
	}

	public List find(String paramString, Object[] paramArrayOfObject,
			PagingBean paramPagingBean) {
		int i = getTotalItems(paramString, paramArrayOfObject).intValue();
		paramPagingBean.setTotalItems(i);
		return find(paramString, paramArrayOfObject,
				paramPagingBean.getFirstResult(), paramPagingBean.getPageSize()
						.intValue());
	}

	public List<T> findByHql(String paramString) {
		return findByHql(paramString, null);
	}

	public void remove(PK paramPK) {
		getHibernateTemplate().delete(get(paramPK));
	}

	public void remove(T paramT) {
		getHibernateTemplate().delete(paramT);
	}

	public Object findUnique(final String hql, final Object values[]) {
		return getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if (values != null) {
					for (int i = 0; i < values.length; i++)
						query.setParameter(i, values[i]);

				}
				return query.uniqueResult();
			}

		});
	}

	public int getCountByFilter(final QueryFilter filter) {
		Integer integer = (Integer) getHibernateTemplate().execute(
				new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Criteria criteria = session.createCriteria(persistType);
						for (int i = 0; i < filter.getCommands().size(); i++) {
							CriteriaCommand criteriacommand = (CriteriaCommand) filter
									.getCommands().get(i);
							if (!(criteriacommand instanceof SortCommandImpl))
								criteria = criteriacommand.execute(criteria);
						}

						criteria.setProjection(Projections.rowCount());
						return criteria.uniqueResult();
					}

				});
		if (integer == null)
			return (new Integer(0)).intValue();
		else
			return integer.intValue();
	}

	public List getAll(final QueryFilter queryFilter) {
		if (StringUtils.isNotEmpty(queryFilter.getFilterName()))
			return getAll2(queryFilter);
		int i = getCountByFilter(queryFilter);
		queryFilter.getPagingBean().setTotalItems(i);
		List list = (List) getHibernateTemplate().execute(
				new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Criteria criteria = session.createCriteria(persistType);
						queryFilter.getAliasSet().clear();
						setCriteriaByQueryFilter(criteria, queryFilter);
						return criteria.list();
					}

				});
		if (queryFilter.isExport()) {
			SimpleDateFormat simpledateformat = new SimpleDateFormat(
					"yyyyMMddhhmmssSSS");
			String s = simpledateformat.format(new Date());
			queryFilter.getRequest().setAttribute("fileName", s);
			queryFilter.getRequest().setAttribute("__exportList", list);
		}
		return list;
	}

	public List getAll2(QueryFilter queryfilter) {
		String s = ((String) querys.get(queryfilter.getFilterName())).trim();
		String s1 = null;
		String s2 = null;
		String s3 = null;
		int i = s.toUpperCase().indexOf(" ORDER BY ");
		int j = s.toUpperCase().indexOf(" WHERE ");
		if (i < 0)
			i = s.length();
		if (j < 0)
			j = s.length();
		if (j < 0) {
			s2 = " where 1=1 ";
		} else {
			s2 = s.substring(j + 7, i);
			logger.debug((new StringBuilder()).append("condition:").append(s2)
					.toString());
			Pattern pattern = Pattern.compile(" GROUP BY [\\w|.]+");
			Matcher matcher = pattern.matcher(s2.toUpperCase());
			if (matcher.find()) {
				s3 = s2.substring(matcher.start(), matcher.end());
				s2 = s2.replace(s3, " ");
			}
			s2 = (new StringBuilder()).append(" where (").append(s2)
					.append(")").toString();
		}
		String s4 = "";
		for (int k = 0; k < queryfilter.getCommands().size(); k++) {
			CriteriaCommand criteriacommand = (CriteriaCommand) queryfilter
					.getCommands().get(k);
			if (criteriacommand instanceof FieldCommandImpl) {
				s2 = (new StringBuilder())
						.append(s2)
						.append(" and ")
						.append(((FieldCommandImpl) criteriacommand)
								.getPartHql()).toString();
				continue;
			}
			if (!(criteriacommand instanceof SortCommandImpl))
				continue;
			if (!"".equals(s4))
				s4 = (new StringBuilder()).append(s4).append(",").toString();
			s4 = (new StringBuilder()).append(s4)
					.append(((SortCommandImpl) criteriacommand).getPartHql())
					.toString();
		}

		s1 = s.substring(0, j);
		if (queryfilter.getAliasSet().size() > 0) {
			int l = s1.indexOf(" FROM ");
			String s5 = null;
			if (l > 0) {
				String s6 = s1.substring(l + 6);
				String as[] = s6.split("[ ]");
				if (as.length > 1 && !as[1].toUpperCase().equals("ORDER")
						&& !as[1].toUpperCase().equals("JOIN"))
					s5 = as[1];
				if (s5 == null) {
					s5 = "vo";
					s1 = s1.replace(as[0], (new StringBuilder()).append(as[0])
							.append(" ").append(s5).toString());
				}
			}
			String s7 = "";
			for (Iterator iterator = queryfilter.getAliasSet().iterator(); iterator
					.hasNext();) {
				String s8 = (String) iterator.next();
				s7 = (new StringBuilder()).append(s7).append(" join ")
						.append(s5).append(".").append(s8).append(" ")
						.append(s8).toString();
			}

			if (!"".equals(s7))
				s1 = (new StringBuilder()).append(s1).append(s7).toString();
		}
		s1 = (new StringBuilder()).append(s1).append(s2).toString();
		if (s3 != null)
			s1 = (new StringBuilder()).append(s1).append(s3).append(" ")
					.toString();
		if (!"".equals(s4))
			s1 = (new StringBuilder()).append(s1).append(" order by ")
					.append(s4).toString();
		else
			s1 = (new StringBuilder()).append(s1).append(s.substring(i))
					.toString();
		Object aobj[] = queryfilter.getParamValueList().toArray();
		int i1 = getTotalItems(s1, aobj).intValue();
		queryfilter.getPagingBean().setTotalItems(i1);
		if (logger.isDebugEnabled())
			logger.debug((new StringBuilder()).append("new hql:").append(s1)
					.toString());
		return find(s1, aobj, queryfilter.getPagingBean().getFirstResult(),
				queryfilter.getPagingBean().getPageSize().intValue());
	}

	public void flush() {
		getHibernateTemplate().flush();
	}

	private Criteria setCriteriaByQueryFilter(Criteria paramCriteria,
			QueryFilter paramQueryFilter) {
		for (int i = 0; i < paramQueryFilter.getCommands().size(); i++)
			paramCriteria = ((CriteriaCommand) paramQueryFilter.getCommands()
					.get(i)).execute(paramCriteria);
		paramCriteria.setFirstResult(paramQueryFilter.getPagingBean()
				.getFirstResult());
		paramCriteria.setMaxResults(paramQueryFilter.getPagingBean()
				.getPageSize().intValue());
		return paramCriteria;
	}

	public void setQuerys(Map<String, String> paramMap) {
		this.querys = paramMap;
	}

	public Long update(final String hql, final Object params[]) {
		return (Long) getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				int i = 0;
				Object aobj[] = params;
				int j = aobj.length;
				for (int k = 0; k < j; k++) {
					Object obj = aobj[k];
					query.setParameter(i++, obj);
				}

				Integer integer = Integer.valueOf(query.executeUpdate());
				return new Long(integer.intValue());
			}

		});
	}

	public boolean checkExist(final String table, final String column,
			final String paraValue) {
		Long localLong = (Long) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session paramSession)
							throws HibernateException, SQLException {
						Query localQuery = paramSession
								.createQuery("select count(*) from " + table
										+ " c where c." + column + " = ?");
						localQuery.setString(0, paraValue);
						return localQuery.uniqueResult();
					}
				});
		return localLong.longValue() == 0L;
	}
}

 